﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using Corona.TagContract;
using Corona.TagToolkit.Exception;

namespace Corona.TagToolkit
{
    /// <summary>
    /// 使用流程：先引入TagToolkit和TagContract
    /// 1.
    /// 2.initAppSupport
    /// 3.可以使用公用函数了
    /// 
    /// 应用应当提供
    /// 1.用于认定资源的查询模式（WeakLink，即一组权重）
    /// 2.应该继承Resource，实现其转化为字串的函数ToString，分析固有标签的函数AnalyseTags
    /// 3.把能唯一对应资源字符串转化为资源的函数STConverter
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public partial class AppSupport<T>
    {
        /// <summary>
        /// 把能唯一对应资源字符串转化为资源的函数
        /// </summary>
        /// <param name="locazier">资源的精确定位字符串，比如文件的路径</param>
        /// <returns>一个资源</returns>
        public delegate T STConverter(string locazier);
        /// <summary>
        /// 状态//TODO
        /// </summary>
        public SupportState State
        {
            get
            {
                if (serverSupport.Factory != null && resourceCfg != null && STconverter != null && database != null)
                {

                    if (serverSupport.Factory.State != System.ServiceModel.CommunicationState.Opened)
                        return SupportState.NotReady;

                    return SupportState.Ready;
                }
                else
                    return SupportState.NotReady;
            }
        }



        internal AppSupport() { }


        internal QueryFactory ResourceCfg
        {
            get { return resourceCfg; }
        }

        internal void initServer(string address)
        {
            serverSupport = new ServerSupport();
            serverSupport.setServer(address);
        }


        /// <summary>
        /// 设置应用需要的权重对应关系
        /// </summary>
        /// <param name="weaklink">类型，权重对</param>
        /// <param name="converter">字串资源转化器</param>
        internal void initAppSupport(WeightVector weaklink, double relevance,STConverter stconverter, String connectionString,String dbProviderName,Verify verify)
        {

            if (weaklink.Keys == null)
                throw new AppSupportInitFailedException("弱连接为空");

            this.weaklink = weaklink;
            resourceCfg = new QueryFactory(weaklink,relevance);
            STconverter = stconverter;
            this.verify = verify;
            database = new StrongLinkDAO<T>();
            database.init(connectionString,dbProviderName);

            Resource<T>.appSupport = this;

            QueryFactory.CriticalName = weaklink.Keys.ElementAt(0);
            foreach (string key in weaklink.Keys)
            {
                if (weaklink[key] > weaklink[QueryFactory.CriticalName])
                    QueryFactory.CriticalName = key;
            }
        }



        internal void SetResource(Resource<T> resource, string locazier)
        {

            if (State == SupportState.Ready)
            {
                resource.value = STconverter(locazier);
                resource.uid = getUid(resource);
            }
            else
            {
                throw new AppSupportNotReadyException("AppSupport状态未Ready");
            }
        }

        /// <summary>
        /// 弱链接的查询工厂
        /// </summary>
        QueryFactory resourceCfg;
        /// <summary>
        /// 强连接数据库
        /// </summary>
        StrongLinkDAO<T> database;

        public StrongLinkDAO<T> Database
        {
            get { return database; }
        }
        /// <summary>
        /// 服务端
        /// </summary>
        ServerSupport serverSupport;
        /// <summary>
        /// 转化器
        /// </summary>
        STConverter STconverter;

        /// <summary>
        /// 程序验证
        /// </summary>
        Verify verify;

        WeightVector weaklink;

        /// <summary>
        /// 仅用于发现新资源时,建立强链接
        /// </summary>
        /// <param name="resource">还得实现了ResourceHandler</param>
        /// <returns>找到的uid</returns>
        long getUid(Resource<T> resource)
        {
            long uid = database.getUid(resource);
            if (uid != -1)
                return uid;
            else//如果找不到，建立强链接
            {
                Query query;
                try
                {
                    query = resourceCfg.CreateQueryWithWeightedName(((IControllable)resource).analyseTags());
                }
                catch (InvalidCastException e)
                {
                    throw new ResourceNotExtendsException();
                }


                uid = serverSupport.Server.GetStrongLink(query.ToString(), verify.ToString());
                if (uid == 0)
                    throw new AppVerifyFailedException();
                else if (uid == -1)
                    throw new ServerException("Server throw Exception on GetStrongLink");
                database.addStrongLink(resource, uid);
                return uid;
  
            }
        }
    }

    public enum SupportState
    {
        Ready, NotReady
    }
}

    

